package uy.com.tsi2G7.superbet.bet.dao;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import uy.com.tsi2G7.superbet.bet.Bet;
import uy.com.tsi2G7.superbet.bet.BetState;
import uy.com.tsi2G7.superbet.bet.CompositeBet;
import uy.com.tsi2G7.superbet.bet.SimpleBet;
import uy.com.tsi2G7.superbet.ui.BetHistoryDescriptor;

public class BetStoreImpl implements BetStore {
	
	private HibernateTemplate hibernateTemplate;

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}

	@Override
	public void storeBet(Bet bet) {
		hibernateTemplate.merge(bet);
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<BetHistoryDescriptor> getlastUserSimpleBetsDescription(final String userId) {
		List<BetHistoryDescriptor> results = hibernateTemplate.find("select new uy.com.tsi2G7.superbet.ui.BetHistoryDescriptor(" +
				"e.name,et.name,m.name,res.name,b.amount,b.date,b.amount*res.winAmount) from" +
				" Event e, EventType et, EventMarket m, EventMarketResult res, SimpleBet b where" +
				" et.id=e.eventTypeId and e.id = m.eventId " +
				"and m.id = res.marketId and b.resultId=res.id and b.userId= ? and composite= ? order by b.date desc",new Object[]{userId,false});
		
		List<CompositeBet> compositeBets= hibernateTemplate.find("from CompositeBet where userId = ?",userId);
		for (CompositeBet compositeBet : compositeBets) {
			final List<Long> ids = new ArrayList<Long>();
			for (SimpleBet simpleBet : compositeBet.getBets()) {
				ids.add(simpleBet.getId());
			}
			results.addAll(hibernateTemplate.executeFind(new QueryHibernateCallback(userId, ids, compositeBet)));
		}		
		return results;
	}

	@Override
	public List<SimpleBet> getOpenBetsByMarketId(long eventTypeId, long marketId) {
		return hibernateTemplate.find("from SimpleBet b where b.eventTypeId=? and b.marketId=? and (b.state=? or b.state=?)"
				,new Object[]{eventTypeId,marketId,BetState.OPEN,BetState.PENDING});
	}

	@Override
	public void closeBet(long id) {
		Bet bet = (Bet) hibernateTemplate.get(Bet.class, id);
		bet.setState(BetState.CLOSED);
		hibernateTemplate.merge(bet);
		
	}

	@Override
	public CompositeBet getOpenCompositeBetBySon(long id) {
		List<CompositeBet> bets =  hibernateTemplate.find("from CompositeBet b where b.state=?",new Object[]{BetState.OPEN});
		for (CompositeBet compositeBet : bets) {
			for (SimpleBet bet : compositeBet.getBets()) {
				if(bet.getId()==id)
					return compositeBet;
			}
		}
		return null;
	}

	private class QueryHibernateCallback implements HibernateCallback{
		
		

		private String userId;
		private List<Long> ids;
		private Bet compositeBet;

		
		
		public QueryHibernateCallback(String userId, List<Long> ids,
				Bet compositeBet) {
			super();
			this.userId = userId;
			this.ids = ids;
			this.compositeBet = compositeBet;
		}



		@Override
		public Object doInHibernate(Session session) throws HibernateException,
				SQLException {
			Query query = session.createQuery("select new uy.com.tsi2G7.superbet.ui.BetHistoryDescriptor(" +
			"e.name,et.name,m.name,res.name,b.amount,b.date,res.winAmount) from" +
			" Event e, EventType et, EventMarket m, EventMarketResult res, SimpleBet b where" +
			" et.id=e.eventTypeId and e.id = m.eventId " +
			"and m.id = res.marketId and b.resultId=res.id and b.userId= ? and b.id in (:ids)order by b.date desc ");
			query.setString(0,userId);
			query.setParameterList("ids",ids);
			List<BetHistoryDescriptor> results = query.list();
			BigDecimal amount=BigDecimal.ONE;
			for (BetHistoryDescriptor history : results) {
				amount.multiply(history.getResult());
			}
			amount=amount.multiply(compositeBet.getAmount());
			for (BetHistoryDescriptor history : results) {
				history.setAmount(amount);
				history.setCompositeId(compositeBet.getId());
			}
			return results;
		}
		
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<BetHistoryDescriptor> getPendingUserBetsDescription(String userId) {
		List<BetHistoryDescriptor> results = hibernateTemplate.find("select new uy.com.tsi2G7.superbet.ui.BetHistoryDescriptor(" +
				"e.name,et.name,m.name,res.name,b.amount,b.date,b.amount*res.winAmount,b.userId,b.resultId,b.eventId,b.marketId,b.eventTypeId) from" +
				" Event e, EventType et, EventMarket m, EventMarketResult res, SimpleBet b where" +
				" et.id=e.eventTypeId and e.id = m.eventId " +
				"and m.id = res.marketId and b.resultId=res.id and b.userBet= ? and b.state= ? and composite= ? and b.userId != ? order by b.date desc",new Object[]{true,BetState.PENDING,false,userId});		
		return results;
	}

	@Override
	public Bet getUserBet(String userId, long marketId, long marketResultId) {
		List<SimpleBet> bets =  hibernateTemplate.find("from SimpleBet b where b.userId=? and b.marketId=? and b.resultId=?",new Object[]{userId,marketId,marketResultId});
		if (!bets.isEmpty()){
			return bets.get(0);
		}
		return null;
	}
	
}
